package com.strongbj.iot.devices.ru.response.coder;

import com.strongbj.iot.devices.ru.message.RUMessage;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

public class RUDecoder extends LengthFieldBasedFrameDecoder {

	// 头部起始码 0x5a 0xa5
	private static final int HEADER_SIZE = 10;
	private static final int CRC_SIZE = 2;
	// 高起始码
	private byte hStart;
	// 低起始码
	private byte lStart;

	// 地址码
	private byte[] address = new byte[3];

	// 类型码
	private byte type;

	// 数据区长度高位
	private short length;

	// 总帧数
	@SuppressWarnings("unused")
	private byte tFrame;

	// 当前帧
	@SuppressWarnings("unused")
	private byte cFrame;

	// 正文
	private byte[] body = new byte[1];

	// CRC
	@SuppressWarnings("unused")
	private short crc;

	/**
	 * 
	 * @param maxFrameLength
	 *            解码时，处理每个帧数据的最大长度
	 * @param lengthFieldOffset
	 *            该帧数据中，存放该帧数据的长度的数据的起始位置
	 * @param lengthFieldLength
	 *            记录该帧数据长度的字段本身的长度
	 * @param lengthAdjustment
	 *            修改帧数据长度字段中定义的值，可以为负数
	 * @param initialBytesToStrip
	 *            解析的时候需要跳过的字节数
	 * @param failFast
	 *            为true，当frame长度超过maxFrameLength时立即报TooLongFrameException异常，为false，读取完整个帧再报异常
	 */
	public RUDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment,
			int initialBytesToStrip, boolean failFast) {
		super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		super.channelInactive(ctx);
		ByteBuf bf = this.internalBuffer();
		bf.release();
	}

	@Override
	protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
		if (in == null) {
			return null;
		}

		// System.out.println("#info 可读信息长度="+in.readableBytes());
		if (in.readableBytes() < HEADER_SIZE) {
			return null;
		}
		if (body != null) { // body不等于空说明上一次读到完整数据了
			hStart = in.readByte();
			if (hStart != Integer.valueOf("5A", 16).byteValue()) {
				return null;
			}
			lStart = in.readByte();
			if (lStart != Integer.valueOf("A5", 16).byteValue()) {
				return null;
			}

			in.readBytes(address);
			type = in.readByte();
			length = in.readShort();
			tFrame = in.readByte();
			cFrame = in.readByte();
			// System.out.println("#info
			// --------------------------------------------------------");
			// System.out.println("#info type="+type);
			// System.out.println("#info length="+length);
		}

		if (in.readableBytes() < length + CRC_SIZE) {
			body = null;
			return null;
		} else {
			body = new byte[length];
			in.readBytes(body);
			crc = in.readShort();
		}

		RUMessage message = new RUMessage(address, type, body);
		return message;
	}
}
